package com.tepth.remote.core.utils.camera;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Build;
import android.support.v4.content.ContextCompat;

import com.tepth.remote.core.utils.file.FileUtil;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Description:图片处理工具类
 *
 * @author Hequn.Lee
 * @date 2018/10/15
 */
public class BitmapUtils {

    /**
     * 字节单位
     */
    private static final int UNIT = 1024;

    /**
     * 剪裁图片
     *
     * @param bitmap        要剪裁的bitmap
     * @param compressRatio 剪裁比例
     * @return 剪裁后的图片
     */
    public static Bitmap cropStatusBar(Bitmap bitmap, int compressRatio) {
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,
                bitmap.getWidth() / compressRatio,
                bitmap.getHeight() / compressRatio, false);
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
            return scaledBitmap;
        }
        int statusBarHeight = CommonUtils.dp2px(24);
        return Bitmap.createBitmap(scaledBitmap, 0,
                statusBarHeight / compressRatio, scaledBitmap.getWidth(),
                scaledBitmap.getHeight() - statusBarHeight / compressRatio);
    }

    /**
     * 将拍照得到的图片按照取景框（亮色区域）的范围进行裁剪.
     * 对于1280x720的屏幕，裁剪起始点为坐标(52, 80)，裁剪后，位图尺寸为896x588.（由layout xml定义的布局计算得到）
     * 以上参数将按照图片的实际大小，进行等比例换算。
     * 设备有无虚拟导航栏均能裁剪到正确的区域。
     *
     * @param originalBitmap 拍照得到的Bitmap
     * @return 裁剪之后的Bitmap
     */
    public static Bitmap crop(Bitmap originalBitmap) {
        double originalWidth = originalBitmap.getWidth();
        double originalHeight = originalBitmap.getHeight();
        //图片真正的宽度除以设计图的宽(1280)，得到相对于设计图的缩放比，用于后续裁剪起点坐标和裁剪区域大小的计算
        double scaleX = originalWidth / 1280;
        //将虚拟导航栏的高度换算为1280x720设计图下所占的高度(px)，若设备没有虚拟导航栏，返回0./*1280x720的设计图下，1dp = 2px*/;
        int navBarHeightPxIn1280x720Ui = CommonUtils.px2dp(CommonUtils.getNavigationBarHeightInPx()) * 2;
        //考虑到虚拟导航栏所占的高度，需要对scaleX进行修正，下面计算修正的倍乘系数
        double scaleXMultiplier = ((double) 1280) / ((double) (1280 - navBarHeightPxIn1280x720Ui));
        //修正scaleX，以保证在有无虚拟导航栏的情况下，裁剪区域均正确
        scaleX = scaleX * scaleXMultiplier;
        double scaleY = originalHeight / 720;
        //在1280x720的设计图上，裁剪起点坐标(52, 80)
        int x = (int) (52 * scaleX + 0.5);
        int y = (int) (80 * scaleY + 0.5);
        //在1280x720的设计图上，裁剪区域大小为896x588
        int width = (int) (896 * scaleX + 0.5);
        int height = (int) (588 * scaleY + 0.5);
        return Bitmap.createBitmap(originalBitmap, x, y, width, height);
    }

    /**
     * 若图片宽小于高，则逆时针旋转90° ; 否则，返回原图片.
     * 适用于调用系统相机进行拍照，且希望图片总是横向的场景；
     * Bitmap占用内存较大，建议先压缩到一个分辨率级别，再进行旋转。
     *
     * @param sourceBitmap 拍照得到的Bitmap
     * @return 若图片宽小于高，返回逆时针旋转90°后的Bitmap ; 否则，返回原Bitmap.
     */
    public static Bitmap rotate(Bitmap sourceBitmap) {
        int sourceWidth = sourceBitmap.getWidth();
        int sourceHeight = sourceBitmap.getHeight();
        //若原图的宽大于高，不需要旋转，直接返回原图
        if (sourceWidth >= sourceHeight) {
            return sourceBitmap;
        }
        Matrix matrix = new Matrix();
        matrix.postRotate(-90);
        return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceWidth, sourceHeight, matrix, true);
    }

    /**
     * 将图片文件压缩到所需的大小，返回位图对象.
     * 若原图尺寸小于需要压缩到的尺寸，则返回原图.
     * 该方法通过分辨率面积得到压缩比，因此不存在图片方向、宽高比的问题.
     *
     * @param filePath        File
     * @param reqSquarePixels 要压缩到的分辨率（面积）
     * @return 压缩后的Bitmap
     */
    public static Bitmap compressToResolution(File filePath, long reqSquarePixels) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath.toString(), options);
        double compressRatio = calculateCompressRatioBySquare(options, reqSquarePixels);
        //解析原图
        Bitmap fullBitmap = BitmapFactory.decodeFile(filePath.toString());
        //创建缩放的Bitmap。这里不用inSampleSize，inSampleSize基于向下采样，节省了Bitmap读入后占用的内存，但Bitmap本身的像素还是那么多，文件大小没有改变。
        return Bitmap.createScaledBitmap(fullBitmap, (int) (options.outWidth / compressRatio), (int) (options.outHeight / compressRatio), false);
    }

    /**
     * 计算压缩比.考虑了options的长宽比可能与req中的比例不同的情况.
     * 该方法通过分辨率面积得到压缩比，因此不存在图片方向、宽高比的问题.
     *
     * @param options         BitmapFactory.Options
     * @param reqSquarePixels 压缩后的分辨率面积
     * @return 计算得到的压缩比
     */
    private static double calculateCompressRatioBySquare(BitmapFactory.Options options, long reqSquarePixels) {
        //原图像素数
        long squarePixels = options.outWidth * options.outHeight;
        //若原图像素数少于需要压缩到的像素数，不压缩（压缩比返回1）
        if (squarePixels <= reqSquarePixels) {
            return 1;
        }
        //面积之比，即压缩比（长度之比）的平方
        double powerScale = ((double) squarePixels) / ((double) reqSquarePixels);
        //开根号得压缩比
        return Math.sqrt(powerScale);
    }

    /**
     * 将Bitmap写入文件，文件位于内置存储上该应用包名目录的cache子目录中.
     *
     * @param bitmap   要写入的Bitmap
     * @param fileName 文件名
     * @return 文件对应的File.
     */
    @SuppressWarnings("ResultOfMethodCallIgnored")
    public static File writeBitmapToFile(Bitmap bitmap, String fileName) {
        File file = FileUtil.createFile(FileUtil.UPDATE_CACHE_IMAGE, fileName);
        FileOutputStream fos;
        try {
            if (file.exists()) {
                file.delete();
            }
            fos = new FileOutputStream(file);
            //JPEG为硬件加速，O(1)时间复杂度，而PNG为O(n)，速度要慢很多，WEBP不常用
            //90%的品质已高于超精细(85%)的标准，已非常精细
            bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
            fos.flush();
            bitmap.recycle();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 绘制水印图片
     *
     * @return 水印图片
     */
    public static Bitmap watermark(String time, Context context) {
        Bitmap watermark;
        // 建立一个空的BItMap
        watermark = Bitmap.createBitmap(400, 100, Bitmap.Config.ARGB_8888);
        // 初始化画布绘制的图像到icon上
        Canvas canvas = new Canvas(watermark);
        // 建立画笔
        Paint photoPaint = new Paint();
        // 获取跟清晰的图像采样
        photoPaint.setDither(true);
        // 过滤一些
        photoPaint.setFilterBitmap(true);
        // 创建一个指定的新矩形的坐标
        Rect src = new Rect(0, 0, watermark.getWidth(), watermark.getHeight());
        // 创建一个指定的新矩形的坐标
        Rect dst = new Rect(0, 50, 0, 50);
        // 将photo 缩放或则扩大到
        canvas.drawBitmap(watermark, src, dst, photoPaint);
        // dst使用的填充区photoPaint
        // 设置画笔
        Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG
                | Paint.DEV_KERN_TEXT_FLAG);
        // 字体大小
        textPaint.setTextSize(40.0f);
        // 采用默认的宽度
        textPaint.setTypeface(Typeface.DEFAULT_BOLD);
        // 采用的颜色
        textPaint.setColor(Color.WHITE);
        textPaint.setAntiAlias(true);
        // 影音的设置
        textPaint.setShadowLayer(3f, 1, 1,
                ContextCompat.getColor(context, android.R.color.black));
        if (time != null) {
            // 绘制上去字，开始未知x,y采用那只笔绘制
            canvas.drawText(time, 0, 50, textPaint);
        }
        //Canvas.ALL_SAVE_FLAG
        canvas.save();
        canvas.restore();
        return watermark;
    }

    /**
     * 加载水印
     */
    public static Bitmap createBitmap(Bitmap src, Bitmap watermark) {
        if (src == null) {
            return null;
        }
        int srcWidth = src.getWidth();
        int srcHeight = src.getHeight();

        int waterWidth = watermark.getWidth();
        int waterHeight = watermark.getHeight();
        // create the new blank bitmap
        // 创建一个新的和src长度宽度一样的位图
        Bitmap result = Bitmap
                .createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
        Canvas cv = new Canvas(result);
        // 在0,0坐标开始画入src
        cv.drawBitmap(src, 0, 0, null);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        // 在src的右下解画入水印图片
        cv.drawBitmap(watermark, srcWidth - waterWidth - 100, srcHeight
                - waterHeight, null);
        // 保存 Canvas.ALL_SAVE_FLAG
        cv.save();
        // 存储
        cv.restore();
        return result;
    }

    /**
     * 质量压缩
     *
     * @param image 要压缩的图片
     * @param max   最大体积
     * @return 压缩后的图片
     */
    public static Bitmap compressBitmap(Bitmap image, int max) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 质量压缩方法，这里100表示不压缩，把压缩后的数据存放到byteArrayOutputStream中
        image.compress(Bitmap.CompressFormat.JPEG, 50, byteArrayOutputStream);
        int options = 100;
        // 循环判断如果压缩后图片是否大于(max)50kb,大于继续压缩
        while (byteArrayOutputStream.toByteArray().length / UNIT > max) {
            // 重置byteArrayOutputStream即清空byteArrayOutputStream
            byteArrayOutputStream.reset();
            // 每次都减少10
            options -= 10;
            // 这里压缩options%，把压缩后的数据存放到byteArrayOutputStream中
            image.compress(Bitmap.CompressFormat.JPEG, options, byteArrayOutputStream);
        }
        // 把压缩后的数据byteArrayOutputStream存放到ByteArrayInputStream中
        ByteArrayInputStream isBm = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        // 把ByteArrayInputStream数据生成图片
        return BitmapFactory.decodeStream(isBm, null, null);
    }
}
